import com.google.gson.Gson;
import com.google.gson.internal.LinkedTreeMap;
import com.sun.org.apache.xerces.internal.dom.PSVIAttrNSImpl;

import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.*;

/**
 * Created by wys on 2017/6/15.
 */
public class JsonToCsv {
    public static void main(String[] args) {
        String target = "/Users/wys/Documents/data/doc/ppo978.csv";
        List<String> l = new ArrayList<>();
        l.add("详细信息,aaaa");
        l.add("详细信息,bbbb");
        l.add("详细信息,cccc");
        l.add("详细信息,dddd");



        //遇到数组与对象
        //如果数组中的记录没有数组和对象 才进行记录  如果有进行递归
        //如果对象中没有数组和对象则返回 否则进行递归

        //list<Map<2个>>  初始化list长度和Map的已知非数组字段补零
        //为map的数组字段填充值  应为是同级数组所以从头开始填充


        try {
            List<String> contentLines = Files.lines(Paths.get("/Users/wys/Documents/data/doc/ppo.json"))
                    .collect(java.util.stream.Collectors.toList());
            System.out.println(contentLines);
            for (String contentLine : contentLines) {
                Gson gson = new Gson();
                Object o = gson.fromJson(contentLine, Object.class);
                //System.out.println(m);
                List<Map<String,String>> rs = new ArrayList<>();
                List<String> heads = new ArrayList<>();
                jsonToCvs(o,rs,0,"",heads);
                List<String> csvTable = createCSVTable(rs,heads);
                byte[] uft8bom={(byte)0xef,(byte)0xbb,(byte)0xbf};
                Files.write(Paths.get(target),uft8bom,StandardOpenOption.CREATE);
                Files.write(Paths.get(target),csvTable,Charset.forName("utf-8") ,StandardOpenOption.APPEND);

                System.out.println(rs);

                //LinkedTreeMap
                //ArrayList
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 把json转换为csv数据
     * @param json            解析出的json信息
     * @param rs              最终生成的结果集
     * @param currentLine     当前数据的行数
     * @param prekey          表头的嵌套前缀
     * @param heads            顺序的表头信息
     */
    private static int jsonToCvs(Object json,List<Map<String,String>> rs,int currentLine,String prekey,List<String> heads){
        System.out.println("xx");
        //如果是个对象  如果拿到的是个对象 肯定是同一行的 不需要改变行号  只有数组才需要改变行号
        if(Map.class.isAssignableFrom(json.getClass())){
            int max = 0;
            Map<String,Object> map = (Map<String,Object>) json;
            Map<String,String> rsMap = getRs(rs,currentLine);

            //list<Map<2个>>  初始化list长度和Map的已知非数组字段补零
            //为map的数组字段填充值  应为是同级数组所以从头开始填充

            for (Map.Entry<String,Object> entry : map.entrySet()) {
                Object innerJson = entry.getValue();
                if(List.class.isAssignableFrom(innerJson.getClass()) || Map.class.isAssignableFrom(innerJson.getClass())){
                    int temp = jsonToCvs(innerJson,rs,currentLine,prekey+entry.getKey()+"_",heads);
                    if(temp>max){
                        max = temp;
                    }
                   // int size = ((List)innerJson).size();
                    //if(size>lines) lines = size;
                    continue;
                }

                //如果是数据
                String innerKey = prekey + entry.getKey();
                if(!heads.contains(innerKey)) heads.add(innerKey);
                if(innerJson.toString().equals("843bdc77cad611929c8d2e5e888ea091")){
                    System.out.println();
                }

                rsMap.put(innerKey,innerJson.toString());

                //System.out.println("Key = " + entry.getKey() + ", Value = " + );
            }
            //rs.add(currentLine,rsMap);
            return max;
        }
        //如果是个数组
        if(List.class.isAssignableFrom(json.getClass())){
            List<Object> list = (List<Object>) json;
            //数组最大长度是行的最大长度是行决定的   但是数组中的每个元素的的下一行判断是下一个数组赋值的时候决定的  这里存放的应该是上一个数组行的最大值  list应该是从第0行开始的  相当于每行的初始行数
            int preMax = 0;
            for (int i = 0;i < list.size();i++){
                Object innerJson = list.get(i);
                if(Map.class.isAssignableFrom(innerJson.getClass()) || List.class.isAssignableFrom(innerJson.getClass())){

                    preMax = jsonToCvs(innerJson,rs,currentLine+i,prekey,heads);  //max
                    currentLine += preMax;
                }else{
                    String innerKey = prekey.substring(0,prekey.length()-1);
                    if(!heads.contains(innerKey)) heads.add(innerKey);
                    if(innerJson.toString().equals("843bdc77cad611929c8d2e5e888ea091")){
                        System.out.println();
                    }
                    getRs(rs,currentLine+i).put(innerKey,innerJson.toString());
                }
            }
            return list.size() -1;
        }
        //如果都不是
        return 0;
    }

    /**
     * 获得结果集中的某行
     * @param rs   结果集
     * @param i    获得结果集的第一个元素
     * @return
     */
    private static Map<String,String>getRs(List<Map<String,String>> rs,int i){
        if(i < rs.size()){
            return rs.get(i);
        }else {
            while (i >= rs.size()){
                rs.add(new HashMap<>());
            }
            return rs.get(i);
        }
    }

    private static List<String> createCSVTable(List<Map<String,String>> rs,List<String> heads){
        List<String> finalRs = new ArrayList<>();
        StringBuilder headInfo = new StringBuilder();
        for (String head : heads) {
            headInfo.append("\"").append(head).append("\"").append(",");
        }
        finalRs.add(headInfo.substring(0,headInfo.length()-1));

        for (Map<String, String> line : rs) {
            StringBuilder temp = new StringBuilder();
            for (String head : heads) {
                temp.append("\"").append(line.getOrDefault(head,"")).append("\"").append(",");
            }
            finalRs.add(temp.substring(0,temp.length()-1).replaceAll("(\r\n|\r|\n|\n\r)"," "));
        }
        return finalRs;
    }
}
